package com.hzp.micromall.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzp.micromall.admin.dao.UmsMenuDao;
import com.hzp.micromall.admin.dto.UmsAdminDto;
import com.hzp.micromall.admin.dto.UpdateAdminPasswordParam;
import com.hzp.micromall.admin.entity.UmsAdminRoleRelation;
import com.hzp.micromall.admin.entity.UmsMenu;
import com.hzp.micromall.admin.entity.UmsRole;
import com.hzp.micromall.admin.service.UmsAdminCacheService;
import com.hzp.micromall.admin.service.UmsAdminRoleRelationService;
import com.hzp.micromall.admin.dao.UmsLoginLogDao;
import com.hzp.micromall.admin.dao.UmsAdminDao;
import com.hzp.micromall.admin.dao.UmsAdminRoleRelationDao;
import com.hzp.micromall.admin.dto.UmsAdminParam;
import com.hzp.micromall.admin.entity.UmsAdmin;
import com.hzp.micromall.admin.dto.UmsAdminLoginLog;
import com.hzp.micromall.admin.feign.AuthService;
import com.hzp.micromall.admin.service.UmsAdminService;
import com.hzp.micromall.common.core.api.CommonPage;
import com.hzp.micromall.common.core.api.CommonResult;
import com.hzp.micromall.common.core.api.ResultCode;
import com.hzp.micromall.common.core.constant.AuthConstant;
import com.hzp.micromall.common.core.entity.UserDto;
import com.hzp.micromall.common.core.exception.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author houzipeng
 * @Date 2022/2/16 23:06
 * @Version 1.0
 */
@Service
public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminDao, UmsAdmin> implements UmsAdminService {

    @Autowired
    private UmsAdminDao adminDao;
    @Autowired
    private UmsMenuDao menuDao;
    @Autowired
    private UmsLoginLogDao loginLogDao;
    @Autowired
    private UmsAdminRoleRelationDao adminRoleRelationDao;
    @Autowired
    private AuthService authService;
    @Autowired
    private UmsAdminCacheService adminCacheService;
    @Autowired
    private UmsAdminRoleRelationService adminRoleRelationService;
    @Autowired
    private HttpServletRequest request;

    @Override
    public UmsAdmin register(UmsAdminParam adminParam) {
        UmsAdmin admin = new UmsAdmin();
        BeanUtil.copyProperties(adminParam, admin);
        // 查询是否有相同用户名的用户
        LambdaQueryWrapper<UmsAdmin> wrapper = new LambdaQueryWrapper();
        wrapper.eq(UmsAdmin::getUsername, admin.getUsername());
        List<UmsAdmin> umsAdmins = adminDao.selectList(wrapper);
        if (CollUtil.isNotEmpty(umsAdmins)) {
            return null;
        }
        // 对密码进行加密
        String encodePassword = BCrypt.hashpw(admin.getPassword());
        admin.setPassword(encodePassword);
        adminDao.insert(admin);
        return admin;
    }

    @Override
    public CommonResult login(String username, String password) {
        if (StrUtil.isEmpty(username) || StrUtil.isEmpty(password)) {
            Asserts.fail("用户名或密码不能为空！");
        }
        Map<String, String> params = new HashMap<>();
        // TODO: 2022/2/21 应该client_id等信息应该由用户请求时传过来
        params.put("client_id", AuthConstant.ADMIN_CLIENT_ID);
        params.put("client_secret", "hzp0413");
        params.put("grant_type", "password");
        params.put("username", username);
        params.put("password", password);
        CommonResult restResult = authService.getAccessToken(params);
        if (ResultCode.SUCCESS.getCode().equals(restResult.getCode()) && restResult.getData() != null) {
            insertLoginLog(username);
        }
        return restResult;
    }

    /**
     * 添加登录记录
     *
     * @param username 用户名
     */
    private void insertLoginLog(String username) {
        UmsAdmin admin = getAdminByUsername(username);
        if (ObjectUtil.isNull(admin)) {
            return;
        }
        UmsAdminLoginLog loginLog = new UmsAdminLoginLog();
        loginLog.setAdminId(admin.getId());
        loginLog.setCreateTime(new Date());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String clientIP = ServletUtil.getClientIP(request, null);
        loginLog.setIp(clientIP);
        loginLogDao.insert(loginLog);
    }

    @Override
    public UmsAdmin getAdminByUsername(String username) {
        LambdaQueryWrapper<UmsAdmin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UmsAdmin::getUsername, username);
        UmsAdmin umsAdmin = adminDao.selectOne(wrapper);
        return umsAdmin;
    }

    @Override
    public UserDto loadUserByUsername(String username) {
        UmsAdmin admin = getAdminByUsername(username);
        if (admin != null) {
            List<UmsRole> roleList = getRoleList(admin.getId());
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(admin, userDto);
            if (CollUtil.isNotEmpty(roleList)) {
                List<String> roleStrList = roleList.stream().map(item -> item.getId() + "_" + item.getName()).collect(Collectors.toList());
                userDto.setRoles(roleStrList);
            }
            return userDto;
        }
        return null;
    }

    @Override
    public List<UmsRole> getRoleList(Long adminId) {
        return adminRoleRelationDao.getRoleList(adminId);
    }

    @Override
    public UmsAdmin getCurrentAdmin() {
        String userStr = request.getHeader(AuthConstant.USER_TOKEN_HEADER);
        if (StrUtil.isEmpty(userStr)) {
            Asserts.fail(ResultCode.TOKEN_INVALID_OR_EXPIRED);
        }
        UserDto userDto = JSONUtil.toBean(userStr, UserDto.class);
        UmsAdmin admin = adminCacheService.getAdmin(userDto.getId());
        if (admin == null) {
            admin = adminDao.selectById(userDto.getId());
            adminCacheService.setAdmin(admin);
        }
        return admin;
    }

    @Override
    public CommonPage<UmsAdmin> list(String keyword, Integer pageSize, Integer pageNum) {
        Page<UmsAdmin> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<UmsAdmin> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(keyword)){
            wrapper.like(UmsAdmin::getUsername, keyword)
                    .or().like(UmsAdmin::getNickname, keyword);
        }
        adminDao.selectPage(page, wrapper);
        return new CommonPage<>(page.getCurrent(), page.getTotal(), page.getSize(), page.getRecords());
    }

    @Override
    public CommonPage<UmsAdminDto> page(String keyword, Integer pageSize, Integer pageNum) {
        Page<UmsAdminDto> page = new Page<>(pageNum, pageSize);
        adminDao.getPageByName(page, keyword);
        return new CommonPage<>(page.getCurrent(), page.getTotal(), page.getSize(), page.getRecords());
    }

    @Override
    public List<UmsMenu> getMenuList(Long adminId) {
        return menuDao.getMenuList(adminId);
    }

    @Override
    public UmsAdmin getAdminById(Long id) {
        return adminDao.selectById(id);
    }

    @Override
    public int updateAdminById(Long id, UmsAdmin admin) {
        admin.setId(id);
        int count = adminDao.updateById(admin);
        adminCacheService.delAdmin(id);
        return count;
    }

    @Override
    public ResultCode updatePassword(UpdateAdminPasswordParam param) {
        LambdaQueryWrapper<UmsAdmin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UmsAdmin::getUsername, param.getUsername());
        UmsAdmin admin = adminDao.selectById(wrapper);
        if (BeanUtil.isEmpty(admin)){
            return ResultCode.USER_NOT_EXIST;
        }
        if (!BCrypt.checkpw(param.getOldPassword(), admin.getPassword())){
            return ResultCode.USER_ACCOUNT_OLD_PASSWORD_ERROR;
        }
        admin.setPassword(BCrypt.hashpw(param.getNewPassword()));
        adminDao.updateById(admin);
        adminCacheService.delAdmin(admin.getId());
        return ResultCode.SUCCESS;
    }

    @Override
    public int updateAdminRoleRelation(Long adminId, List<Long> roleIds) {
        int count = roleIds == null ? 0 : roleIds.size();
        //先删除原来的关系
        LambdaQueryWrapper<UmsAdminRoleRelation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UmsAdminRoleRelation::getAdminId, adminId);
        adminRoleRelationDao.delete(wrapper);
        //建立新关系
        if (CollUtil.isNotEmpty(roleIds)) {
            List<UmsAdminRoleRelation> list = new ArrayList<>();
            for (Long roleId : roleIds) {
                UmsAdminRoleRelation roleRelation = new UmsAdminRoleRelation();
                roleRelation.setAdminId(adminId);
                roleRelation.setRoleId(roleId);
                list.add(roleRelation);
            }
            adminRoleRelationService.saveBatch(list);
        }
        return count;
    }

    @Override
    public int deleteAdminById(Long id) {
        int count = adminDao.deleteById(id);
        adminCacheService.delAdmin(id);
        return count;
    }
}
